package com.googlecode.allinclusive.fw.core.jms;

import java.io.Serializable;

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.Message;
import javax.jms.MessageProducer;
import javax.jms.ObjectMessage;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.naming.Context;
import javax.naming.NamingException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;

import com.googlecode.allinclusive.fw.core.config.GlobalConfig;
import com.googlecode.allinclusive.fw.core.springframework.utils.SpringUtils;

public class JMSUtils {
	
	private static final Log log = LogFactory.getLog(JMSUtils.class);
	// --- with spring -----------------------------------------------------------------------------------------
	/**
	 * Send Message With Spring
	 * @param senderName
	 * @param serObj
	 */
	public static void send(final String senderName, final Serializable serObj) {
		JmsTemplate jmsTemplate = SpringUtils.getBean(senderName, JmsTemplate.class);
		send(jmsTemplate, serObj);
	}
	
	/**
	 * Send Message With Spring
	 * @param jmsTemplate
	 * @param serObj
	 */
	public static void send(final JmsTemplate jmsTemplate, final Serializable serObj) {
		jmsTemplate.send(new MessageCreator(){
			public Message createMessage(Session session) throws javax.jms.JMSException {
				return session.createObjectMessage(serObj);
			}
		});
	}
	
	// --- without spring --------------------------------------------------------------------------------
	/**
	 * Send Message
	 * @param queueName
	 * @param serObj
	 */
	public void sendMsg(final String queueName, final Serializable serObj) {
		sendMsg(null, queueName, serObj);
	}
	
	/**
	 * Send Message
	 * @param config
	 * @param queueName
	 * @param serObj
	 */
	public void sendMsg(final JMSConfig config, final String queueName, final Serializable serObj) {
		Connection conn = null;
		Session sess = null;
		MessageProducer mp = null;
		try {
			// Load JMS Configuration
			JMSConfig jmsConfig = config;
			if (jmsConfig == null) {
				jmsConfig = JMSUtils.getDefaultConfig();
			}
			// Create Context
			Context ctx = jmsConfig.createContext();
			// Look up ConnectionFactory & Destination
			ConnectionFactory cf = (ConnectionFactory) ctx.lookup(jmsConfig.getJmsConnectionFactory());
			Destination destination = (Destination) ctx.lookup(queueName);
			// Create Connection & Session & MessageProducer
			conn = cf.createConnection();
			sess = conn.createSession(true, Session.AUTO_ACKNOWLEDGE);
			mp = sess.createProducer(destination);
			// Create Message
			Message message = sess.createObjectMessage(serObj);
			// Send Message
			mp.send(message);
		} catch (NamingException e) {
			// TODO throw CustomException
			throw new JMSException(e.getMessage(), e);
		} catch (javax.jms.JMSException e) {
			// TODO throw CustomException
			throw new JMSException(e.getMessage(), e);
		} finally {
			try {
	            if(mp != null) { mp.close(); }
	            if(sess != null) { sess.close(); } 
	            if(conn != null) { conn.close(); }
			} catch (javax.jms.JMSException e) {
				// TODO ignore
				log.warn(e);
			}
		}
	}
	
	/**
	 * Send Queue Message
	 * @param queueName
	 * @param serObj
	 */
	public static void sendMQMsg(final String queueName, final Serializable serObj) {
		sendMQMsg(null, queueName, serObj); 
	}
	
	/**
	 * Send Queue Message
	 * @param config
	 * @param queueName
	 * @param serObj
	 */
	public static void sendMQMsg(final JMSConfig config, final String queueName, final Serializable serObj) {
		QueueConnection qconn = null;
		QueueSession qsess = null;
		QueueSender qsender = null;
		try {
			// Load JMS Configuration
			JMSConfig jmsConfig = config;
			if (jmsConfig == null) {
				jmsConfig = JMSUtils.getDefaultConfig();
			}
			// Create Context
			Context ctx = jmsConfig.createContext();
			// Look up ConnectionFactory
			QueueConnectionFactory cf = 
				(QueueConnectionFactory) ctx.lookup(jmsConfig.getJmsConnectionFactory());
			// Create Connection & Session & Queue Sender
			qconn = cf.createQueueConnection();
			qconn.start();
			qsess = qconn.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);
			Queue queue = (Queue) ctx.lookup(queueName);
			qsender = qsess.createSender(queue);
			// Create Message
			ObjectMessage objMessage = qsess.createObjectMessage(serObj);
			// Send Message
			qsender.send(objMessage);
		} catch (NamingException e) {
			// TODO throw CustomException
			throw new JMSException(e.getMessage(), e);
		} catch (javax.jms.JMSException e) {
			// TODO throw CustomException
			throw new JMSException(e.getMessage(), e);
		} finally {
			try {
	            if(qsender != null) { qsender.close(); }
	            if(qsess != null) { qsess.close(); } 
	            if(qconn != null) { qconn.close(); }
			} catch (javax.jms.JMSException e) {
				// TODO ignore
				log.warn(e);
			}
		}
	}
	
	/**
	 * Get Default JMS Configuration
	 * @return JMS Configuration
	 */
	public static JMSConfig getDefaultConfig() {
		JMSConfig jmsConfig = new JMSConfig();
		jmsConfig.setInitialFactory(GlobalConfig.getProperty("java.naming.factory.initial"));
		jmsConfig.setFactoryUrlPkgs(GlobalConfig.getProperty("java.naming.factory.url.pkgs"));
		jmsConfig.setProviderUrl(GlobalConfig.getProperty("java.naming.provider.url"));
		jmsConfig.setJmsConnectionFactory(GlobalConfig.getProperty("jms.connectionfactory.jndi"));
		return jmsConfig;
	}
}
